package com.example.security.assembly;

import com.example.base.utils.RedisUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * 用来判断是否登录 做自定义权限控制
 */
@Slf4j
@Component
public class SysAuthenticatedAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    public static final String ROLE_BACKEND_INTERFACE_LIST = "role:backendInterface:";

    private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

    @Override
    public AuthorizationDecision check(Supplier<Authentication> supplier, RequestAuthorizationContext context) {
        Authentication authentication = supplier.get();
        //此处判断是否登录
        boolean granted = this.isGranted(authentication);
        if (!granted){
            log.info("请求当前接口, 请先登录");
            return new AuthorizationDecision(false);
        }
        HttpServletRequest request = context.getRequest();
        if (Objects.isNull(request)){
            return new AuthorizationDecision(false);
        }
        //获取用户角色能够获取的请求后端接口
        List<String> backend = backendInterfaceList(authentication.getAuthorities());
        if (CollectionUtils.isEmpty(backend)){
            return new AuthorizationDecision(false);
        }
        String uri = request.getRequestURI();
        //是否能够调用后端接口
        return new AuthorizationDecision(backend.contains(uri));
    }

    private boolean isGranted(Authentication authentication) {
        return authentication != null && this.isNotAnonymous(authentication) && authentication.isAuthenticated();
    }

    private boolean isNotAnonymous(Authentication authentication) {
        return !this.trustResolver.isAnonymous(authentication);
    }

    /**
     * 获取用户能够调用的后端接口
     * @param authorities   用户角色
     * @return
     */
    private List<String> backendInterfaceList(Collection<? extends GrantedAuthority> authorities){
        List<String> backendInterfaceList = Lists.newArrayList();
        for (GrantedAuthority authority : authorities){
            ArrayNode arrayNode = RedisUtil.getValue(ROLE_BACKEND_INTERFACE_LIST + authority.getAuthority(), ArrayNode.class);
            if (Objects.isNull(arrayNode)){
                continue;
            }
            for (JsonNode node : arrayNode){
                backendInterfaceList.add(node.textValue());
            }
        }
        return backendInterfaceList;
    }
}
